package com.CST.service.impl.ys;
import com.CST.common.StaticVariable;
import com.CST.common.constant.Constants;
import com.CST.dto.ys.*;
import com.CST.entity.cb.BdSysUser;
import com.CST.entity.ys.YsAppealRecord;
import com.CST.entity.ys.YsComplaint;
import com.CST.entity.ys.YsFileUpload;
import com.CST.entity.ys.YsSubject;
import com.CST.mapper.cst.cb.BdSysUserMapper;
import com.CST.mapper.cst.ys.*;
import com.CST.service.ys.YsAppealRecordService;
import com.CST.service.ys.YsComplaintService;
import com.CST.util.FileUtils;
import com.CST.util.HttpUtil;
import com.CST.vo.ys.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.rmi.RemoteException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ellen
 * @since 2023-04-27
 */
@Service
public class YsAppealRecordServiceImpl extends ServiceImpl<YsAppealRecordMapper, YsAppealRecord> implements YsAppealRecordService {


    @Value("${uploadAddr}")
    private  String path;
    private final YsAppealRecordMapper appealDao;
    private final YsAccountDetailMapper accountDao;
    private final YsIndexDetailMapper indexDao;
    private final YsAssetDetailMapper assetDao;
    private final BdSysUserMapper userMapper;
    private final YsFileUploadMapper fileUpload;
    private final YsComplaintService complaintService;
    private final YsSubjectMapper ysSubjectMapper;

    public YsAppealRecordServiceImpl(YsAppealRecordMapper appealDao,
                                     YsAccountDetailMapper accountDao,
                                     YsIndexDetailMapper indexDao,
                                     YsAssetDetailMapper assetDao,
                                     BdSysUserMapper userMapper,
                                     YsFileUploadMapper fileUpload, YsComplaintService complaintService,
                                     YsSubjectMapper ysSubjectMapper) {
        this.appealDao = appealDao;
        this.accountDao = accountDao;
        this.indexDao = indexDao;
        this.assetDao = assetDao;
        this.userMapper = userMapper;
        this.fileUpload = fileUpload;
        this.complaintService = complaintService;
        this.ysSubjectMapper = ysSubjectMapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer addAppeal(AppealDTO dto, HttpServletRequest request) throws IOException {
        Optional.ofNullable(dto.getSource())
                .orElseThrow(()->new RuntimeException("来源不能为空"));
        Optional.ofNullable(dto.getNum())
                .orElseThrow(()->new RuntimeException("编码不能为空"));
        // 资产类数据 有subjectCode
        if(!dto.getSource().equals(3)&&!dto.getSource().equals(5)){
            Optional.ofNullable(dto.getSubjectId())
                    .orElseThrow(()->new RuntimeException("subject_id不能为空"));
        }
        // 业务量配套指标没有院区 num 作为主键
        if(dto.getSource()!=4){
            Optional.ofNullable(dto.getYard())
                    .orElseThrow(()->new RuntimeException("院区编码不能为空"));
        }

        Integer re =  this.checkAuth(dto.getSource(),dto.getNum(),dto.getYard());
        if(re>0){
            throw new RemoteException("还有未处理的同一条申诉记录");
        }

        YsAppealRecord record = new YsAppealRecord();
        if(dto.getFile()!=null && dto.getFile().size()>0){
            //设置文件地址
            List<Long> ids = fileUpload.selectIn(splitUrl(dto.getFile()));
            uploadFileReturnAddr(record,ids);
        }
        // 判断申诉人
        BdSysUser user = userMapper.getUserById(HttpUtil.getRequestHeaderInfo(Constants.USER_ID));
        Optional.ofNullable(user).orElseThrow(()-> new RuntimeException("用户未登录"));

        //申诉消息
        // 来源 1业务职能，2管理职能-费用类，3管理职能资本类。4管理职能业务配套指标
        if(!dto.getSource().equals(3)&&!dto.getSource().equals(5)){
            complaintService.saveEntity(YsComplaint.builder()
                    .recipient(StaticVariable.LOG_YS_COMPLAINT_RECIPIENT_1)
                    .source(StaticVariable.LOG_YS_COMPLAINT_SOURCE_1)
                    .operate(StaticVariable.LOG_YS_COMPLAINT_OPERATE_1)
                    .acceptContent(user.getDeptName() + "对" +
                            ysSubjectMapper.selectById(dto.getSubjectId()) .getSubjectCode()
                            + StaticVariable.LOG_YS_COMPLAINT_CONTEXT_1)
                    .jumpPage(StaticVariable.LOG_YS_COMPLAINT_PAGE_1)
                    .complaintUser(user.getId())
                    .build());
        }else{
            complaintService.saveEntity(YsComplaint.builder()
                    .recipient(StaticVariable.LOG_YS_COMPLAINT_RECIPIENT_1)
                    .source(StaticVariable.LOG_YS_COMPLAINT_SOURCE_1)
                    .operate(StaticVariable.LOG_YS_COMPLAINT_OPERATE_1)
                    .acceptContent(user.getDeptName() + "对"
                            + assetDao.getAssetByNum(dto.getNum(),dto.getYard()).getSubjectCode()
                            + StaticVariable.LOG_YS_COMPLAINT_CONTEXT_1)
                    .jumpPage(StaticVariable.LOG_YS_COMPLAINT_PAGE_1)
                    .complaintUser(user.getUserName())
                    .build());
        }

        record.setAppealer(user.getId());
        record.setSource(dto.getSource());
        record.setStatus(0);// 待处理
        record.setAppealTime(LocalDateTime.now());
        record.setMemo(dto.getMemo());
        record.setNum(dto.getNum()); //预算执行 编码
        record.setSubjectID(dto.getSubjectId());
        if(dto.getSource()==4){
            record.setYard(-1);
        }else {
            record.setYard(dto.getYard());
        }
        return  appealDao.insert(record);
    }


    private Integer checkAuth(Integer source, Integer num, Integer yard) {
        if(!source.equals(4)){
            return appealDao.selectBySNY(source, num, yard);
        }else{
            return appealDao.selectBySN(source, num);
        }
    }

    private void uploadFileReturnAddr(YsAppealRecord record,List<Long> files){
        StringBuilder sb;
        if(files!=null && files.size() >0){
            // 上传文件
            sb = new StringBuilder();
            for (Long t:files){
                sb.append(t);
                // 拼接文件地址
                sb.append(";");
            }
            sb.deleteCharAt(sb.length()-1);
            record.setFileAddr(sb.toString());
        }
    }

    @Override
    public List<YsAppealRecordVO> pageByUser(YsAppealDTO dto, HttpServletRequest request) {
        dto.setUser(HttpUtil.getRequestHeaderInfo(Constants.USER_ID));
        return appealDao.pageByUser(dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateRecord(UpdateDTO dto) {
        Optional.ofNullable(dto.getId())
                .orElseThrow(()->new RuntimeException("申诉记录为空"));
        YsAppealRecord record = appealDao.selectById(dto.getId());
        // 有新增有删除
        if (record!=null){
            // 申诉时间
            record.setAppealTime(LocalDateTime.now());
            //申诉备注
            record.setMemo(dto.getMemo());
            List<String> ids = new ArrayList<>();
            if (record.getFileAddr() != null){
                if (record.getFileAddr().contains(";")){
                    ids = Arrays.asList(record.getFileAddr().split(";"));
                } else {
                    ids.add(record.getFileAddr());
                }

            }

            List<Long> oldIds = new ArrayList<>();
            for (String s : ids) {
                oldIds.add(Long.parseLong(s));
            }

            if (dto.getFile().size() > 0){
                List<String> urls =  splitUrl(dto.getFile());
                List<Long> newIds = fileUpload.selectIn(urls);

                //交集
                List<Long> union = oldIds.stream().filter(newIds::contains).collect(Collectors.toList());
                //新增文件
                newIds.removeAll(union);
                //新的文件地址
                if(newIds.size()>0){
                    newIds.addAll(union);
                    //设置新的上传文件地址
                    uploadFileReturnAddr(record,newIds);
                }

                //删除文件
                oldIds.removeAll(union);
                if(oldIds.size()>0){
                    //删除 文件上传记录
                    fileUpload.deleteBatchIds(oldIds);
                    List<YsFileUpload> oldFiles = fileUpload.selectBatchIds(oldIds);
                    //删除真实文件
                    for(YsFileUpload f:oldFiles) {
                        FileUtils.deleteFiles(f.getUuidName());
                    }
                }
            } else {
                fileUpload.deleteBatchIds(oldIds);
                List<YsFileUpload> oldFiles = fileUpload.selectBatchIds(oldIds);
                //删除真实文件
                for(YsFileUpload f:oldFiles) {
                    FileUtils.deleteFiles(f.getUuidName());
                }
            }
            return updateById(record);
        }
        return false;
    }

    private List<String> splitUrl(List<String> files) {
        List<String> urls = new ArrayList<>();
        for(String f:files){
            urls.add(f.replace(path,""));
        }
        return urls;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public YsRecordWithAccountVO getRecordAccountDetail(YsAppealRecord record,Integer type) {
        //业务预算信息
        AccountDetailVO detailVo = accountDao.getAccountByNum(record.getNum(), record.getYard(),type);
        YsRecordWithAccountVO accountVO = new YsRecordWithAccountVO();
        //设置申诉信状态
        switch (record.getStatus()){
            case 0:
                accountVO.setResult("待处理");break;
            case 1:
                accountVO.setResult("已驳回");break;
            case 2:
                accountVO.setResult("已修正");break;
            default:
                break;
        }
        accountVO.setAdvice(record.getAdvice());
        //设置处理人
        if(!StringUtils.isEmpty(record.getHandler())){
            BdSysUser user = userMapper.getUserById(record.getHandler());
            accountVO.setHandler(user.getRealName());
        }
        accountVO.setAccountDetailVo(detailVo);
        accountVO.setAdvice(record.getAdvice());
        accountVO.setHandleTime(record.getHandleTime());
        accountVO.setMemo(record.getMemo());
        if(!StringUtils.isEmpty(record.getFileAddr())){
            List<YsFileUpload> files = fileUpload.selectBatchIds(Arrays.asList(record.getFileAddr().split(";")));
            // 获取文件地址
            List<FileVO> fileVOList = new ArrayList<>();
            if(files.size()>0){
                for (YsFileUpload file : files) {
                    FileVO fileVO = new FileVO();
                    fileVO.setName(file.getFileName());
                    fileVO.setUrl(path+file.getUuidName());
                    fileVOList.add(fileVO);
                }
            }
            accountVO.setFiles(fileVOList);
        }
        return accountVO;
    }

    @Override
    public YsRecordWithExpenseVO getRecordExpenseDetail(YsAppealRecord record,Integer type) {
        AccountDetailVO detailVo = accountDao.getAccountByNum(record.getNum(), record.getYard(), type);
        YsRecordWithExpenseVO expenseVO = new YsRecordWithExpenseVO();
        switch (record.getStatus()){
            case 0:
                expenseVO.setResult("待处理");break;
            case 1:
                expenseVO.setResult("已驳回");break;
            case 2:
                expenseVO.setResult("已修正");break;
            default:
                break;
        }
        expenseVO.setAdvice(record.getAdvice());
        //设置处理人
        if(!StringUtils.isEmpty(record.getHandler())){
            BdSysUser user = userMapper.getUserById(expenseVO.getHandler());
            expenseVO.setHandler(user.getRealName());
        }
        expenseVO.setAccountDetailVo(detailVo);
        expenseVO.setHandleTime(record.getHandleTime());
        expenseVO.setMemo(record.getMemo());
        if(!StringUtils.isEmpty(record.getFileAddr())){
            List<YsFileUpload> files = fileUpload.selectBatchIds(Arrays.asList(record.getFileAddr().split(";")));
            // 获取文件地址
            List<FileVO> fileVOList = new ArrayList<>();
            if(files.size()>0){
                for (YsFileUpload file : files) {
                    FileVO fileVO = new FileVO();
                    fileVO.setName(file.getFileName());
                    fileVO.setUrl(path+file.getUuidName());
                    fileVOList.add(fileVO);
                }
            }
            expenseVO.setFiles(fileVOList);
        }
        return expenseVO;
    }

    @Override
    public YsRecordWithAssetVO getRecordAssetDetail(YsAppealRecord record) {
        AssetDetailVO entry = assetDao.getAssetByNum(record.getNum(), record.getYard());
        YsRecordWithAssetVO assetVO = new YsRecordWithAssetVO();
        assetVO.setDetailVO(entry);
        switch (record.getStatus()){
            case 0:
                assetVO.setResult("待处理");break;
            case 1:
                assetVO.setResult("已驳回");break;
            case 2:
                assetVO.setResult("已修正");break;
            default:
                break;
        }
        assetVO.setAdvice(record.getAdvice());
        //设置处理人
        if(!StringUtils.isEmpty(record.getHandler())){
            BdSysUser user = userMapper.getUserById(record.getHandler());
            assetVO.setHandler(user.getRealName());
        }
        assetVO.setMemo(record.getMemo());
        assetVO.setHandleTime(record.getHandleTime());
        assetVO.setId(record.getId());
        if(!StringUtils.isEmpty(record.getFileAddr())){
            List<YsFileUpload> files = fileUpload.selectBatchIds(Arrays.asList(record.getFileAddr().split(";")));
            // 获取文件地址
            List<FileVO> fileVOList = new ArrayList<>();
            if(files.size()>0){
                for (YsFileUpload file : files) {
                    FileVO fileVO = new FileVO();
                    fileVO.setName(file.getFileName());
                    fileVO.setUrl(path+file.getUuidName());
                    fileVOList.add(fileVO);
                }
            }
            assetVO.setFiles(fileVOList);
        }
        return assetVO;
    }

    @Override
    public YsRecordWithIndexVO getRecordIndexDetail(YsAppealRecord record) {
        YsIndexDetailsVO entry = indexDao.getIndexById(record.getNum());
        YsRecordWithIndexVO indexVO = new YsRecordWithIndexVO();
        indexVO.setEntry(entry);
        switch (record.getStatus()){
            case 0:
                indexVO.setResult("待处理");break;
            case 1:
                indexVO.setResult("已驳回");break;
            case 2:
                indexVO.setResult("已修正");break;
            default:
                break;
        }
        indexVO.setAdvice(record.getAdvice());
        //设置处理人
        if(!StringUtils.isEmpty(record.getHandler())){
            BdSysUser user = userMapper.getUserById(record.getHandler());
            indexVO.setHandler(user.getRealName());
        }
        indexVO.setMemo(record.getMemo());
        indexVO.setHandleTime(record.getHandleTime());
        indexVO.setId(record.getId());

        if(!StringUtils.isEmpty(record.getFileAddr())){
            List<YsFileUpload> files = fileUpload.selectBatchIds(Arrays.asList(record.getFileAddr().split(";")));
            // 获取文件地址
            List<FileVO> fileVOList = new ArrayList<>();
            if(files.size()>0){
                for (YsFileUpload file : files) {
                    FileVO fileVO = new FileVO();
                    fileVO.setName(file.getFileName());
                    fileVO.setUrl(path+file.getUuidName());
                    fileVOList.add(fileVO);
                }
            }
            indexVO.setFiles(fileVOList);
        }
        return indexVO;
    }

    @Override
    public List<YsHandleVO> getAllRecord(HandleDTO dto) {
        return appealDao.getAllRecord(dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer reject(HandleAppealDTO dto, HttpServletRequest request) {
        Optional.ofNullable(dto.getAdvice()).orElseThrow(()->
                new RuntimeException("驳回，建议不能为空"));
        YsAppealRecord record = appealDao.selectById(dto.getId());
        Optional.ofNullable(record).orElseThrow(()->new RuntimeException("记录不存在"));

        //更新申诉记录
        record.setAdvice(dto.getAdvice());
        record.setStatus(1);

        BdSysUser user = userMapper.getUserById(HttpUtil.getRequestHeaderInfo(Constants.USER_ID));
        Optional.ofNullable(user).orElseThrow(()-> new RuntimeException("用户未登录"));
        record.setHandler(user.getId());
        record.setHandleTime(LocalDateTime.now());
        Integer t = appealDao.updateById(record);
        if(!record.getSource().equals(3)){
            YsSubject ysSubject = ysSubjectMapper.selectById(record.getSubjectID());
            Optional.ofNullable(ysSubject).orElseThrow(()-> new RuntimeException("预算科目不存在"));
            complaintService.saveEntity(YsComplaint.builder()
                    .recipient(StaticVariable.LOG_YS_COMPLAINT_RECIPIENT_2)
                    .source(StaticVariable.LOG_YS_COMPLAINT_SOURCE_2)
                    .operate(StaticVariable.LOG_YS_COMPLAINT_OPERATE_3)
                    .acceptContent(StaticVariable.LOG_YS_COMPLAINT_CONTEXT_HEAD_1
                            + ysSubject.getSubjectName() +"("
                            + ysSubject.getSubjectCode() + ")"
                            + StaticVariable.LOG_YS_COMPLAINT_CONTEXT_2)
                    .jumpPage(StaticVariable.LOG_YS_COMPLAINT_PAGE_2)
                    .complaintUser(user.getUserName())
                    .build());
        }else{
            AssetDetailVO asset = assetDao.getAssetByNum(record.getNum(), record.getYard());
            Optional.ofNullable(asset).orElseThrow(()-> new RuntimeException("原始数据已删除或被更新"));
            complaintService.saveEntity(YsComplaint.builder()
                    .recipient(StaticVariable.LOG_YS_COMPLAINT_RECIPIENT_2)
                    .source(StaticVariable.LOG_YS_COMPLAINT_SOURCE_2)
                    .operate(StaticVariable.LOG_YS_COMPLAINT_OPERATE_3)
                    .acceptContent(StaticVariable.LOG_YS_COMPLAINT_CONTEXT_HEAD_1
                            + asset.getSubjectName() +"("
                            + asset.getSubjectCode() + ")"
                            + StaticVariable.LOG_YS_COMPLAINT_CONTEXT_2)
                    .jumpPage(StaticVariable.LOG_YS_COMPLAINT_PAGE_2)
                    .complaintUser(user.getUserName())
                    .build());
        }
        return t;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer undoRecord(Long id) {
        YsAppealRecord record = appealDao.selectById(id);
        List<String> fileId = new ArrayList<>();

        if (record.getFileAddr() != null){
            if (record.getFileAddr().contains(";")){
                fileId = Arrays.asList(record.getFileAddr().split(";"));
            } else {
                fileId.add(record.getFileAddr());
            }
            List<YsFileUpload> uploads = fileUpload.selectBatchIds(fileId);
            List<String> fileAddr = uploads.stream().map(YsFileUpload::getUuidName).collect(Collectors.toList());
            fileAddr.forEach(FileUtils::deleteFiles);
            //删除记录
            fileUpload.deleteBatchIds(uploads.stream().map(YsFileUpload::getId).collect(Collectors.toList()));
        }
        return appealDao.deleteById(id);
    }

}
